﻿// Class to start, stop, shutdown the service
// <copyright file="PstBackup2013Service.cs" company="EasyCompany">
// EasyCompany
// </copyright>
namespace PstBakup2013Server
{
    using System;
    using System.ServiceProcess;

    /// <summary>
    /// The service class. Responsible for starting, stopping and shutting down the service.
    /// </summary>
    public class PstBackup2013Service : System.ServiceProcess.ServiceBase
    {
        /// <summary>
        /// Field to store the service object
        /// </summary>
        private static PstBackup2013Service service;

        /// <summary>
        /// Field that reference the server Class
        /// </summary>
        private Server server;

        /// <summary>
        /// Settings for the server that listen clients messages and reports request.
        /// </summary>
        private static Server.Settings serverSettings = new Server.Settings();

        /// <summary>
        /// Field to reference the thread where 'server' is executed
        /// </summary>
        private System.Threading.Thread serverThread;

        /// <summary>
        /// Initializes a new instance of the <see cref="PstBackup2013Service" /> class. Set Service parameters.
        /// </summary>
        public PstBackup2013Service()
        {
            this.ServiceName = "PstBakup2013Server";
            this.EventLog.Log = "Application";
            this.AutoLog = true;
            this.CanHandlePowerEvent = true;
            this.CanHandleSessionChangeEvent = true;
            this.CanPauseAndContinue = false;
            this.CanShutdown = true;
            this.CanStop = true;
        }

        /// <summary>
        /// Main entry point for the service. initialize the Server Port.
        /// </summary>
        /// <param name="args">Must contains one, and only one, argument. Which must be greater than 1024. It will be use as Server Port. If no or invalid argument are provided, default value will be used.</param>
        public static void Main(string[] args)
        {
            service = new PstBackup2013Service();

            if (args != null && args.Length == 1)
            {
                service.EventLog.WriteEntry("Initializing Server settings from : " + args[0].ToString(), System.Diagnostics.EventLogEntryType.Information);

                if (System.IO.File.Exists(args[0]))
                    ReadServerSettings(args[0]);
            }
            else
            {
                service.EventLog.WriteEntry("One, and only one, argument must be provide.", System.Diagnostics.EventLogEntryType.Error);
            }

            service.EventLog.WriteEntry("Server will listen clients on Port : " + serverSettings.ClientsPort.ToString() + " and report requests on Port : " + serverSettings.ReportsPort.ToString(), System.Diagnostics.EventLogEntryType.Information);
            ServiceBase.Run(service);
        }

        /// <summary>
        /// Start the service.
        /// </summary>
        /// <param name="args">No arguments require.</param>
        protected override void OnStart(string[] args)
        {
            service.EventLog.WriteEntry("Service is starting (Port : " + serverSettings.ClientsPort.ToString() + ")...", System.Diagnostics.EventLogEntryType.Information, 0);
            try
            {
                this.server = new Server(serverSettings);
                this.serverThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.server.Start));
                this.serverThread.Start();
            }
            catch (Exception ex)
            {
                service.EventLog.WriteEntry("An error occurred while trying to start Server : " + ex.Message, System.Diagnostics.EventLogEntryType.Error, 10);
                this.ExitCode = -1;
            }
        }

        /// <summary>
        /// Stop the service.
        /// </summary>
        protected override void OnStop()
        {
            service.EventLog.WriteEntry("Service is stopping...", System.Diagnostics.EventLogEntryType.Information, 1);
            try
            {
                this.server.Stop();
                System.Threading.Thread.Sleep(1000);
                this.serverThread = null;
            }
            catch (Exception ex)
            {
                service.EventLog.WriteEntry("An error occured while trying to stop Server : " + ex.Message, System.Diagnostics.EventLogEntryType.Error, 11);
            }
        }

        /// <summary>
        /// Shutdown the service.
        /// </summary>
        protected override void OnShutdown()
        {
            service.EventLog.WriteEntry("Service is stopping because the server is shutting down...", System.Diagnostics.EventLogEntryType.Information, 2);
            this.OnStop();
            this.ExitCode = 0;
        }

        private static void ReadServerSettings(string xmlConfigurationFile)
        {
            try
            {
                System.IO.StreamReader reader = new System.IO.StreamReader(xmlConfigurationFile);

                System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
                doc.LoadXml(reader.ReadToEnd());

                System.Xml.XmlNode root = doc.DocumentElement;
                System.Xml.XmlNode clientsPortNode = root.SelectSingleNode("ClientsPort");
                System.Xml.XmlNode ReportsPortNode = root.SelectSingleNode("ReportsPort");

                serverSettings.ClientsPort = Convert.ToInt32(clientsPortNode.InnerText);
                serverSettings.ReportsPort = Convert.ToInt32(ReportsPortNode.InnerText);
            }
            catch (Exception ex)
            {
                service.EventLog.WriteEntry("Unable to initialize settings with : " + xmlConfigurationFile + " : " + ex.Message);
            }
        }
    }
}
